home *** CD-ROM | disk | FTP | other *** search
- /* Solution to the August 1992 MacTutor Programmers' Challenge
- *
- * Submitted by Greg Landweber on September 9, 1992
- *
- * Address: 10 Wallingford Drive
- * Princeton, NJ 08540
- * Phone: (609) 452-2655
- * E-mail: landwebe@math.rutgers.edu (Peter Landweber's account)
- */
-
- #define max 13 /* The number of holes in a row or column.
- * NOTE: I assume that the holes start with 0
- * if the holes start with 1, change max to 14.
- */
-
- void BandedPegs (numPegs, pegsPtr, numEdgePegsPtr, edgePegsPtr, areaPtr)
- short numPegs;
- Point *pegsPtr;
- short *numEdgePegsPtr;
- Point *edgePegsPtr;
- Fixed *areaPtr;
- {
- short xLeft[max],xRight[max]; /* leftmost and rightmost peg in each row */
- short top,bottom; /* top and bottom rows containing pegs */
- short x,y; /* horizontal and vertical coords. of peg */
- short area; /* used to compute twice the enclosed area */
- short numLeft,numRight; /* number of pegs on left and right side */
- Point leftPegs[max],rightPegs[max]; /* array of pegs on left and right */
- short index; /* general use array index */
- Point *pegPtr1,*pegPtr2; /* for stepping through arrays of Points */
-
- /* Fill xLeft[v] and xRight[v] with the h-coords
- * of the leftmost and rightmost pegs in row v.
- * If there are no pegs in row v, then set
- * xLeft[v] = max, and
- * xRight[v] = -1.
- * Note that any pegs inbetween the leftmost and
- * rightmost pegs in a row will automatically be
- * in the interior of the rubber band polygon.
- * This reduces the maximum number of pegs to 26.
- */
-
- for ( index = 0; index < max; index++ ) {
- xLeft [index] = max;
- xRight[index] = -1;
- }
-
- pegPtr1 = pegsPtr;
- for ( index = numPegs; index > 0; index-- ) {
- y = pegPtr1->v;
- x = pegPtr1->h;
- if ( x < xLeft [y] )
- xLeft [y] = x;
- if ( x > xRight[y] )
- xRight[y] = x;
- pegPtr1++;
- }
-
- /* Find the bottom (lowest v) and top (highest v) rows containing pegs. */
-
- bottom = -1;
- while ( xLeft [++bottom] == max );
-
- top = max;
- while ( xLeft [--top] == max );
-
- /* Fill leftPegs[] with a list of all the pegs
- * on the left side of the convex polygon from
- * the top (hi v) to the bottom (lo v), and put
- * the number of those pegs - 1 in numLeft.
- */
-
- leftPegs[0].h = xLeft[top]; /* leftPegs[0] is the topmost (highest v) */
- leftPegs[0].v = top; /* point on the left side of the polygon. */
- numLeft = 0; /* Index of the last peg in leftPegs[]. */
-
- for (y = top - 1; y >= bottom; y--) /* Add pegs from the top to the bottom. */
- if ( (x = xLeft[y]) != max ) { /* Check if there is a peg in row y. */
- pegPtr1 = leftPegs; /* Note thatpegPtr2 is the current peg */
- pegPtr2 = pegPtr1++; /* in the list and pegPtr1 is the next. */
- for ( index = 0; index < numLeft; index++ )
-
- /* Is the peg at {x,y} to the left of */
- /* the line from *pegPtr1 to *pegPtr2? */
- if ( ( (x - pegPtr1->h) * (pegPtr2->v - pegPtr1->v) ) <
- ( (pegPtr2->h - pegPtr1->h) * (y - pegPtr1->v) ) )
- numLeft = index;
- /* If so, all the pegs from pegPtr1 on */
- /* will be to the right of the line */
- /* from {x,y} to *pegPtr2, and so we */
- /* remove them from the left peg list. */
- else /* If not, we go on to the next peg. */
- pegPtr2 = pegPtr1++;
- numLeft++; /* Tack {x,y} onto the end of the list. */
- pegPtr1->v = y;
- pegPtr1->h = x;
- }
-
- /* Fill rightPegs[] with a list of all the pegs
- * on the right side of the convex polygon from
- * the top (hi v) to the bottom (lo v), and put
- * the number of those pegs - 1 in numRight.
- */
-
- rightPegs[0].h = xRight[top]; /* rightPegs[0] is the topmost (highest v) */
- rightPegs[0].v = top; /* point on the right side of the polygon. */
- numRight = 0; /* Index of the last peg in rightPegs[]. */
-
- for (y = top - 1; y >= bottom; y--) /* Add pegs from the top to the bottom. */
- if ( (x = xRight[y]) != max ) { /* Check if there is a peg in row y. */
- pegPtr1 = rightPegs; /* Note that pegPtr2is the current peg */
- pegPtr2 = pegPtr1++; /* in the list and pegPtr1 is the next. */
- for ( index = 0; index < numRight; index++ )
-
- /* Is the peg at {x,y} to the right of */
- /* the line from *pegPtr1 to *pegPtr2? */
- if ( ( (x - pegPtr1->h) * (pegPtr2->v - pegPtr1->v) ) >
- ( (pegPtr2->h - pegPtr1->h) * (y - pegPtr1->v) ) )
- numRight = index;
- /* If so, all the pegs from pegPtr1 on */
- /* will be to the left of the line */
- /* from {x,y} to *pegPtr2, and so we */
- /* remove them from the right peg list. */
- else /* If not, we go on to the next peg. */
- pegPtr2 = pegPtr1++;
- numRight++; /* Tack {x,y} onto the end of the list. */
- pegPtr1->v = y;
- pegPtr1->h = x;
- }
-
- /* Copy the contents of numLeft[] and numRight[] into edgePegsPtr. */
-
- pegPtr2 = edgePegsPtr;
-
- pegPtr1 = leftPegs + 1;
- for ( index = numLeft - 1; index > 0; index-- )
- *(pegPtr2++) = *(pegPtr1++);
-
- /* Do the pegs all lie on the same line? */
- /* If so, the left and right are the same. */
- if ( *( (long *)leftPegs + 1 ) != *( (long *)rightPegs + 1 ) ) {
- pegPtr1 = rightPegs + 1;
- for ( index = numRight - 1; index > 0; index-- )
- *(pegPtr2++) = *(pegPtr1++);
- }
-
- /* Put all the pegs in the top and bottom rows into edgePegsPtr. */
-
- pegPtr1 = pegsPtr;
- for ( index = numPegs; index > 0; index-- ) {
- if ( (pegPtr1->v == top) || (pegPtr1->v == bottom) )
- *(pegPtr2++) = *pegPtr1;
- pegPtr1++;
- }
-
- /* Figure out how many pegs there are touching the edge of the polygon. */
-
- *numEdgePegsPtr = pegPtr2 - edgePegsPtr;
-
- /* Compute twice the area to the left of the right side of the polygon. */
-
- area = 0; /* The area of a trapezoid with height h and parallel */
- /* sides of length a and b is h*(a+b)/2. Here we have */
- /* h = pegPtr2->v - pegPtr1->v, */
- /* a = pegPtr2->h, and b = pegPtr1->h . */
-
- pegPtr1 = rightPegs; /* Loop through all of the line segments on */
- for ( index = numRight; index > 0; index-- ) {
- pegPtr2 = pegPtr1++; /* the right side of the convex polygon. */
- area += (pegPtr2->v - pegPtr1->v) * (pegPtr2->h + pegPtr1->h);
- }
-
- /* Subtract twice the area to the left of the left side of the polygon. */
-
- pegPtr1 = leftPegs; /* Loop through all of the line segments on */
- for ( index = numLeft; index > 0; index-- ) {
- pegPtr2 = pegPtr1++; /* the left side of the convex polygon. */
- area -= (pegPtr2->v - pegPtr1->v) * (pegPtr2->h + pegPtr1->h);
- }
-
- /* Finally, divide by two and convert the result to type Fixed. */
-
- *areaPtr = FixRatio( area, 2 );
- }
-